<?php

/*
 * This is my first OOP project. This is a test project!
 * The name of project is Bookstore. 
 */

/**
 * This class is handling information about users.
 * @author Velislav Belev
 * @license   http://opensource.org/licenses/gpl-3.0.html GNU Public License
 */
namespace Models;
class User extends \MysqliDb {
    private $_email;
    private $_valueToCheck;
    protected $_queryResult; 

/**
 * This method is to trim and validate data by minimum length. 
 * @param int, str $valueToCheck
 * @param int $minLength
 * @param str $errMsg
 * @param int $errCode
 * @return int, str
 * @throws \Exception
 */
    public function validate($valueToCheck, $minLength, $errMsg, $errCode) {
        $valueToCheck = trim($valueToCheck);
        if (mb_strlen($valueToCheck) < $minLength) {
            throw new \Exception($errMsg, $errCode);
        }
        return $this->_valueToCheck = $valueToCheck;        
    }    

  
      /**
       * This method validates email.
       * @param str $email
       * @return str
       * @throws \Exception\
       */  
    public function validateEmail($email) {
        $email = strtolower(trim($email));   
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)){
                throw new \Exception('Invalid email address', 108);
        } else {
                return $this->_email = $email;
          }
    }
    
    
    private function _isInDb($tableName, $columnName, $valueToCheck) {
       $tableName = trim($tableName);
       $tableName = $this->escape($tableName);
       $columnName = trim($columnName);
       $columnName =  $this->escape($columnName);
          
        if(is_array($valueToCheck)) { 
            $valueToCheck = array_map('trim',$valueToCheck);
            $valueToCheck = array_map('intval',$valueToCheck); 
            $valueToCheck = array_map('mysql_real_escape_string',$valueToCheck);
            $this->where($columnName, array( 'in' =>  $valueToCheck));
            $queryResult = $this->_queryResult  = $this->get($tableName); 
        } else {
            $valueToCheck = intval(trim($valueToCheck));
            $valueToCheck = $this->escape($valueToCheck);
            $this->where($columnName, $valueToCheck);
        $this->_queryResult = $this->get($tableName); 
        }      
    }   

    
    /**
     * This method is to check if value is in the DB. Returns number of affected rows.
     * @param str $tableName
     * @param str $columnName
     * @param str $valueToCheck
     * @return int - numbers of rows
     */
    public function isInDb($tableName, $columnName, $valueToCheck) {
        $this->_isInDb($tableName, $columnName, $valueToCheck);
        $count = count($this->_queryResult);
        return $count;      
    }    
    
    

    /**
     * This method saves user in the DB.
     * @param str $userName
     * @param str $password
     * @param str $email
     * @throws \Exception
     */
    public function registration($userName, $password, $email) {
            $userName = strtolower($userName);
            $userName = $this->validate($userName, 4, 
                    'User name must be at least 4 characters long', 109);
            $password = $this->validate($password, 4, 
                    'Password must be at least 4 characters long', 110);            
            $email = $this->validateEmail($email);
            
            $isUserNameFree = $this->isInDb('users', 'user_name', $userName);

            if($isUserNameFree != 0) {
                throw new \Exception('This user name is NOT free', 111);
            }
            $isEmailFree = $this->isInDb('users', 'email', $email);
            if($isEmailFree != 0) {
                throw new \Exception('This email address is not free', 112);
            }
            
            $userName = $this->escape($userName);
            $password = PasswordHash::hash($password);
            $password = $this->escape($password);
            $email = $this->escape($email);
            
            $insertData = array('user_name' => $userName, 
                'email' => $email, 'password' => $password);
           $isSave = $this->insert('users', $insertData);
           if($isSave != 0){
               echo '<p>Registration successful! Please, 
                   <a href="login.php">go to Login page</a></p>';
           } else {
               throw new \Exception('Error in saving', 113);
           }     
    }
    
    /**
     * This method is to login. 
     * @param str $userName
     * @param str $password
     * @throws \Exception
     */
    public function login($userName, $password) { 
        $userName = trim($userName);
        $userName = $this->escape($userName);
        $password = trim($password);
        $password = $this->escape($password);
        
        $this->where('user_name', $userName);
        $isUser = $this->get('users');
        if(count($isUser) == 1) {
            foreach ($isUser as $value) {
                $hash = $value['password'];
                $userId = $value['user_id'];
            }

            $password = PasswordHash::match($password, $hash);
                if($password === true) {
                    $this->where('is_admin', 1);
                    $this->where('user_name', $userName);
                    $isAdmin = $this->get('users');                    
                    if(count($isAdmin) == 1) {
                        $_SESSION['userId'] = $userId;
                        $_SESSION['isLogged'] = 2;
                        header ('Location: index.php');
                    } else {
                        $_SESSION['userId'] = $userId;
                        $_SESSION['isLogged'] = 1;
                        header ('Location: index.php');                        
                    }

                } else {
                throw new \Exception('Wrong user name or password', 114);
            }
            
        } else {
            throw new \Exception('Wrong user name or password', 114);
        }
    }
    
    /**
     * This method is used when user goes to registration page. 
     * If user is logged he is redirected to home page.
     */
    public static function redirectLogged(){
        if (isset($_SESSION['isLogged'])) {
            if ($_SESSION['isLogged'] == 1) {
                header ('Location: index.php');
                exit;       
            }
        } 
    }
    
    /**
     * By this method I get user name by user id.
     * @param int $userId
     * @return str
     * @throws \Exception
     */
    public static function getUserName($userId){
        $user = new User();
        $isUserIdExists = $user->isInDb('users', 'user_id', $userId);
        if($isUserIdExists == 1) {
            $userId = $user->escape($userId);
            $user->where('user_id', $userId);
            $q = $user->get('users');
            foreach ($q as $value) {
               return ucfirst($userId = $value['user_name']);
            }
        } else {
             throw new \Exception('Invalid User ID', 130);
        }
    }
    
}
